package com.hermeneute.fsa.editors;

import java.io.StringReader;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.resources.IWorkspaceRoot;

import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IStatusLineManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.editors.text.TextEditor;
import org.eclipse.ui.part.FileEditorInput;
import org.eclipse.ui.progress.IProgressConstants;
import org.eclipse.ui.texteditor.MarkerUtilities;
import org.eclipse.ui.views.contentoutline.ContentOutlinePage;
import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
import org.xml.sax.SAXParseException;

import antlr.RecognitionException;
import antlr.SemanticException;
import antlr.TokenStreamException;
import antlr.TokenStreamIOException;
import antlr.TokenStreamRecognitionException;

import com.hermeneute.fsa.editors.outline.OutlineContentProvider;
import com.hermeneute.fsa.editors.outline.OutlineLabelProvider;
import com.hermeneute.fsa.parser.ExtentLexerSharedInputState;
import com.hermeneute.fsa.parser.FSTLexer;
import com.hermeneute.fsa.parser.FSTParser;
import com.hermeneute.fsa.parser.FSTParserTree;
import com.hermeneute.fsa.parser.FSTParserTreeTK;
import com.hermeneute.fsa.parser.TokenAST;
import com.hermeneute.fsa.parser.ValueExtentToken;

public class FSAEditor extends TextEditor {
	public static final String ERROR_MARKER_ID = "com.hermeneute.editor.error";

	protected IContentOutlinePage contentOutlinePage;

	protected TreeViewer contentOutlineViewer;

	protected Viewer currentViewer;

	FSTParserTree parser = null;

	class MyContentOutlinePage extends ContentOutlinePage {
		public void createControl(Composite parent) {
			super.createControl(parent);
			contentOutlineViewer = getTreeViewer();
			contentOutlineViewer.addSelectionChangedListener(this);
			contentOutlineViewer
					.setContentProvider(new OutlineContentProvider());
			contentOutlineViewer.setLabelProvider(new OutlineLabelProvider());
			contentOutlineViewer.setInput(FSAEditor.this);
		}

		int indexOfLine(int ln) {
			String editorText = getDocumentProvider().getDocument(
					getEditorInput()).get();
			int pos = 0;
			if (ln == 1)
				return pos;

			for (int i = 0; i < ln - 1; i++) {
				pos = editorText.indexOf('\n', pos) + 1;
			}
			return pos;
		}

		@Override
		public void selectionChanged(SelectionChangedEvent event) {
			super.selectionChanged(event);
			ISelection selection = event.getSelection();

			if (selection.isEmpty())
				FSAEditor.this.resetHighlightRange();
			else {
				TokenAST c = (TokenAST) ((IStructuredSelection) selection)
						.getFirstElement();
				int start = indexOfLine(c.getToken().getLine())
						+ c.getToken().getColumn();
				int length = c.getToken().getText().length();
				try {
					setHighlightRange(start, length, true);
				} catch (IllegalArgumentException x) {
					resetHighlightRange();
				}
			}

		}

		public void makeContributions(IMenuManager menuManager,
				IToolBarManager toolBarManager,
				IStatusLineManager statusLineManager) {
			super.makeContributions(menuManager, toolBarManager,
					statusLineManager);
			// contentOutlineStatusLineManager = statusLineManager;
		}

		public void setActionBars(IActionBars actionBars) {
			super.setActionBars(actionBars);
			// getActionBarContributor().shareGlobalActions(this, actionBars);
		}
	}

	public IContentOutlinePage getContentOutlinePage() {
		if (contentOutlinePage == null) {
			contentOutlinePage = new MyContentOutlinePage();
			contentOutlinePage
					.addSelectionChangedListener(new ISelectionChangedListener() {
						public void selectionChanged(SelectionChangedEvent event) {
						}
					});
		}

		return contentOutlinePage;
	}

	public Object getAdapter(Class required) {
		if (IContentOutlinePage.class.equals(required)) {
			if (contentOutlinePage == null) {
				contentOutlinePage = getContentOutlinePage();
			}
			return contentOutlinePage;
		}
		return super.getAdapter(required);
	}

	private ColorManager colorManager;

	public FSAEditor() {
		super();
		colorManager = new ColorManager();
		setSourceViewerConfiguration(new FSAConfiguration(colorManager));
		setDocumentProvider(new FSADocumentProvider());
	}

	public void dispose() {
		colorManager.dispose();
		super.dispose();
	}

	@Override
	public void createPartControl(Composite parent) {
		super.createPartControl(parent);
	}

	@Override
	public void doSave(IProgressMonitor progressMonitor) {
		super.doSave(progressMonitor);
		// ((OutlineContentProvider)contentOutlineViewer.getContentProvider()).getParser().clearErrors();
		try {
		contentOutlineViewer.refresh();
		final FSTParserTreeTK p = ((OutlineContentProvider) contentOutlineViewer
				.getContentProvider()).getParser();
		if (p.getParser().getErrors().size() > 0) {
			markError(p.getParser());
		} else {
			removeExistingMarkers();
			Job job = new Job("Compiling ") {
				public boolean isModal(Job job) {
					Boolean isModal = (Boolean) job
							.getProperty(IProgressConstants.PROPERTY_IN_DIALOG);
					if (isModal == null)
						return false;
					return isModal.booleanValue();
				}

				protected Action getQueryCompletedAction() {
					return new Action("Compiling Status") {
						public void run() {
							MessageDialog.openInformation(getSite().getShell(),
									"Compiling Complete",
									"Automaton file has been completed");
						}
					};
				}

				public IStatus run(IProgressMonitor monitor) {
					try {
						IStatus status = doFinish(monitor, p.getParser()
								.getNumberOfStatement());
						if (isModal(this)) {
							// The progress dialog is still open so
							// just open the message
							// showResults();
						} else {
							setProperty(IProgressConstants.KEEP_PROPERTY,
									Boolean.TRUE);
							setProperty(IProgressConstants.ACTION_PROPERTY,
									getQueryCompletedAction());
						}
						monitor.done();
						return status;
					} catch (Exception e) {
						e.printStackTrace();
						monitor.done();
					}
					return null;
				}
			};
			job.setUser(true);
			job.schedule();
		} 
		}catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	public void doSaveAs() {
		super.doSaveAs();
		doSave(new NullProgressMonitor());
	}

	IStatus doFinish(IProgressMonitor m, int max) {
		String editorText = getDocumentProvider().getDocument(getEditorInput()).get();
		StringReader rdr = new StringReader(editorText);
		ExtentLexerSharedInputState lsis = new ExtentLexerSharedInputState(rdr);

		FSTLexer lexer = new FSTLexer(lsis);
		FSTParser p = new FSTParser(lexer);
		p.setPM(m);
		p.setProject(((FileEditorInput)getEditorInput()).getFile().getProject());
		p.setPath(((FileEditorInput)getEditorInput()).getFile().getParent().getFullPath());
		m.beginTask("Compiling Automaton", max);
		//
		try {
			p.file();
		} catch (OperationCanceledException e) {
			return Status.CANCEL_STATUS;
		} catch (RecognitionException e) {
			e.printStackTrace();
		} catch (TokenStreamException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}

		return Status.OK_STATUS;
	}

	protected void markError(FSTParserTree p) {
		System.out.println("Marking errors");
		IFile file = getInputFile();
		Map map = new HashMap();
		removeExistingMarkers();
		Set errors = p.getErrors();

		for (Object e : errors) {
			int line = -1;
			int col = -1;
			String message = null;

			System.out.println("Error " + e);
			if (e instanceof RecognitionException) {
				RecognitionException error = (RecognitionException) e;
				line = error.getLine();
				message = error.getMessage();
			}
			if (e instanceof SemanticException) {
				SemanticException error = (SemanticException) e;
				line = error.getLine();
				message = error.getMessage();
			}
			if (e instanceof TokenStreamRecognitionException) {
				TokenStreamRecognitionException error = (TokenStreamRecognitionException) e;
				line = p.getLine();
				message = error.getMessage();
			}

			if (e instanceof TokenStreamIOException) {
				TokenStreamIOException error = (TokenStreamIOException) e;
				line = p.getLine();
				message = error.getMessage();
			}
			MarkerUtilities.setLineNumber(map, line);
			MarkerUtilities.setMessage(map, message);
			map.put(IMarker.LOCATION, file.getFullPath().toString());
			map.put(IMarker.SEVERITY, new Integer(IMarker.SEVERITY_ERROR));

			try {
				MarkerUtilities.createMarker(file, map, ERROR_MARKER_ID);
			} catch (CoreException ee) {
				ee.printStackTrace();
			}

		}
	}

	protected IFile getInputFile() {
		IFile file = null;
		try {
			IFileEditorInput ife = (IFileEditorInput) getEditorInput();
			file = ife.getFile();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return file;
	}

	public void removeExistingMarkers() {
		IFile file = getInputFile();
		try {
			file.deleteMarkers(ERROR_MARKER_ID, true, IResource.DEPTH_ZERO);
		} catch (CoreException e1) {
			e1.printStackTrace();
		}
	}
}
